package com.joolun.mall.service.impl;

import cn.binarywang.wx.miniapp.bean.shortlink.GenerateShortLinkRequest;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.Query;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.joolun.common.exception.CustomException;
import com.joolun.common.utils.SecurityUtils;
import com.joolun.common.utils.StringUtils;
import com.joolun.mall.entity.*;
import com.joolun.mall.mapper.ChainMapper;
import com.joolun.mall.mapper.ChainOrderMapper;
import com.joolun.mall.mapper.ChainPlanMapper;
import com.joolun.mall.mapper.SkuBasicMapper;
import com.joolun.mall.service.IChainDetailService;
import com.joolun.mall.service.IChainPlanService;
import com.joolun.mall.service.IChainService;
import com.joolun.mall.util.WxUtil;
import com.joolun.weixin.config.WxMaConfiguration;
import lombok.AllArgsConstructor;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 品牌Service业务层处理
 * 
 * @author www.joolun.com
 * @date 2025-05-20
 */
@Service
@AllArgsConstructor
public class ChainServiceImpl extends ServiceImpl<ChainMapper, Chain> implements IChainService
{
    @Autowired
    private IChainDetailService chainDetailService;
    
    @Autowired
    private ChainPlanMapper  chainPlanMapper;

    @Autowired
    private ChainOrderMapper orderMapper;

    @Autowired
    private SkuBasicMapper skuBasicMapper;


    @Override
    public Page<Chain> page1(Page<Chain> page, Chain dto){
        return baseMapper.page1(page,dto);
    }

    @Override
    public Chain detail(Long id,boolean checkDelete) {
        Chain chain = super.getById(id);
        if(Objects.isNull(chain) || (checkDelete && !"0".equals(chain.getDelFlag()))){
            throw new CustomException("接龙不存在");
        }

        ChainPlan chainPlan = chainPlanMapper.selectById(chain.getPlanId());
        chain.setRemind(chainPlan.getRemind());

        List<ChainDetail> chainDetails = chainDetailService.list(
                Wrappers.query(new ChainDetail()).lambda()
                        .eq(ChainDetail::getDelFlag, "0")
                        .eq(ChainDetail::getChainId, chain.getId())
        );
        chain.setDetails(chainDetails);
        //处理排序
        addSizeSort(chainDetails);
        dealState(chain);
        return chain;
    }

    private void addSizeSort(List<ChainDetail> chainDetails) {
        List<Long> skuIds = chainDetails.stream().map(ChainDetail::getSkuId).distinct().collect(Collectors.toList());
        if(CollectionUtil.isNotEmpty(skuIds)){
            List<SkuBasic> skuBasics = skuBasicMapper.selectList(
                    Wrappers.query(new SkuBasic()).lambda()
                            .eq(SkuBasic::getIsDelete, "0")
                            .in(SkuBasic::getSkuId, skuIds)
            );

            Map<Integer, Integer> skuSortMap = skuBasics.stream().filter(e -> Objects.nonNull(e.getSort()))
                    .collect(Collectors.toMap(
                            SkuBasic::getSkuId,
                            SkuBasic::getSort,
                            (existing, replacement) -> existing
                    ));
            chainDetails.forEach(chainDetail -> {
                Integer sizeSort = skuSortMap.get(chainDetail.getSkuId().intValue());
                chainDetail.setSizeSort(Objects.isNull(sizeSort) ? 0 : sizeSort);
            });
        }
    }

    private void dealState(Chain chain) {
        if(chain.getEndDate().before(new Date())){
            chain.setLinkState(20);
        }
        else if(chain.getBeginDate().after(new Date())){
            chain.setLinkState(0);
        }else{
            chain.setLinkState(10);
        }
    }

    @Transactional
    @Override
    public void addLinks(List<Chain> chains) {
        checkAdd(chains);
        chains.forEach(chain -> {
            chain.setCreateBy(SecurityUtils.getUsername());
            chain.setCreateTime(new Date());
        });

        //todo 校验需要做
        this.saveBatch(chains);
        chains.forEach(chain -> {
            chain.setWxLink(genLink(chain));
        });
        this.saveOrUpdateBatch(chains);
        List<ChainDetail> addChainDetails = new ArrayList<>();
        chains.forEach(chain -> {
            List<ChainDetail> chainDetails = chain.getDetails();
            if(CollectionUtil.isNotEmpty(chainDetails)){
                chainDetails.forEach(e -> {
                    if(Objects.nonNull(chain.getMaxPickNum()) && Objects.nonNull(e.getMaxSpuNum()) && e.getMaxSpuNum() > chain.getMaxPickNum()){
                        throw new CustomException(e.getSpuCode()+"款号，同款件数超过最大可选件数，请检查");
                    }
                    if(e.getMaxSpuNum() > 10){
                        throw new CustomException(e.getSpuCode()+"同款件数不能超过10件");
                    }
                    e.setChainId(chain.getId());
                    e.setPlanId(chain.getPlanId());
                    e.setCreateBy(SecurityUtils.getUsername());
                    e.setCreateTime(new Date());
                });
                addChainDetails.addAll(chainDetails);
            }
        });
        if(CollectionUtil.isNotEmpty(addChainDetails)){
            chainDetailService.saveBatch(addChainDetails);
        }
    }

    private void checkAdd(List<Chain> chains) {

        List<Chain> dbChains = baseMapper.selectList(Wrappers.<Chain>lambdaQuery().in(Chain::getPlanId, chains.get(0).getPlanId()).eq(Chain::getDelFlag, "0"));

        //已经已经完成的链接允许新增同样的sku
        List<Long> filterFinishedIds = dbChains.stream().filter(e -> e.getEndDate().before(new Date())).map(Chain::getId).collect(Collectors.toList());
        List<ChainDetail> dbDetails = chainDetailService.list(
                Wrappers.<ChainDetail>lambdaQuery()
                        .in(ChainDetail::getPlanId, chains.get(0).getPlanId())
                        .eq(ChainDetail::getDelFlag, "0")
                        .notIn(CollectionUtil.isNotEmpty(filterFinishedIds),ChainDetail::getChainId, filterFinishedIds)
        );

        Set<String> spuCodes = new HashSet<>();
        chains.forEach(e ->{
            checkMustFiled(e);
            // 校验接龙里面名称相同的款 的最大同款件数是否相同 是否有相同的颜色规格
            checkSpuColorSize(e);

            e.getDetails().forEach(e1 -> {
               spuCodes.add(e1.getSpuCode());
           });
        });

        dbChains.addAll(chains);
        checkNameUnique(dbChains);
        Set<String> dbSpuCodes = dbDetails.stream().filter(e -> Objects.nonNull(e.getSpuCode())).map(ChainDetail::getSpuCode).collect(Collectors.toSet());
        List<String> alreadyExistsSpuCodes = spuCodes.stream().filter(dbSpuCodes::contains).collect(Collectors.toList());
        if(CollectionUtil.isNotEmpty(alreadyExistsSpuCodes)){
            throw new CustomException(String.join(",", alreadyExistsSpuCodes) +"款号在该计划中已存在，请检查");
        }

    }

    // 校验接龙里面名称相同的款 的最大同款件数是否相同 是否有相同的颜色规格
    private static void checkSpuColorSize(Chain e) {
        Map<String, List<ChainDetail>> chainDetailGroup = e.getDetails().stream()
                .collect(
                        Collectors.groupingBy(
                                ChainDetail::getSpuName,
                                LinkedHashMap::new,
                                Collectors.toList()
                        )
                );

        chainDetailGroup.forEach((spuName, chainDetails) -> {
            //判断相同颜色是否存在于两个款号中 如果存在报错
            long maxSpuNumCount = chainDetails.stream().map(ChainDetail::getMaxSpuNum).distinct().count();
            // 去重后应该只有一个最大同款件数
            if(1 != maxSpuNumCount){
                throw new CustomException("不允许存在相同商品名称同款件数不同，或颜色尺码相同的款号请检查");
            }
            //判断相同颜色是否存在于两个款号中 如果存在报错
            Map<String, List<ChainDetail>> colorSizeGroup = chainDetails.stream()
                    .collect(
                            Collectors.groupingBy(
                                    chainDetail -> chainDetail.getColor()+"_"+chainDetail.getSize(),
                                    LinkedHashMap::new,
                                    Collectors.toList()
                            )
                    );
            colorSizeGroup.forEach(
                    (color, details) -> {
                        long maxColorCount = details.stream().map(ChainDetail::getSpuCode).distinct().count();
                        if(maxColorCount > 1){
                            throw new CustomException("不允许存在相同商品名称同款件数不同，或颜色尺码相同的款号请检查");
                        }
                    }
            );
        });
    }

    private static void checkNameUnique(List<Chain> dbChains) {
        Map<String, List<Chain>> datas = dbChains.stream().collect(Collectors.groupingBy(Chain::getName));
        datas.forEach((k,v) -> {
            if(v.size() > 1){
                throw new CustomException("链接名称重复【"+ k +"】，请检查");
            }
        });
    }

    private static void checkMustFiled(Chain e) {
        if(Objects.isNull(e.getBeginDate()) || Objects.isNull(e.getEndDate())){
            throw new CustomException("接龙开始时间和结束时间不能为空");
        }
        if(StringUtils.isBlank(e.getPics())){
            throw new CustomException("链接图片不能为空");
        }
        if(StringUtils.isBlank(e.getName())){
            throw new CustomException("链接名称不能为空");
        }
        if(StringUtils.isBlank(e.getDetail())){
            throw new CustomException("链接介绍不能为空");
        }
    }


    @Transactional
    @Override
    public void updateLink(Chain chain) {

        Chain dbChain = baseMapper.selectById(chain.getId());

        checkUpdate(chain,dbChain);

        chain.setUpdateBy(SecurityUtils.getUsername());
        chain.setUpdateTime(new Date());

        //强制更新某几个字段
        LambdaUpdateWrapper<Chain> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(Chain::getMaxChainNum, chain.getMaxChainNum());
        updateWrapper.set(Chain::getMaxPickNum, chain.getMaxPickNum());
        updateWrapper.eq(Chain::getId, chain.getId());
        this.update(chain, updateWrapper);

        List<ChainDetail> details = chain.getDetails();
        //查询库中的接龙明细
        List<ChainDetail> dbChainDetails = chainDetailService.list(
                Wrappers.query(new ChainDetail()).lambda()
                        .eq(ChainDetail::getDelFlag, "0")
                        .in(ChainDetail::getChainId, chain.getId())
        );

        //新增
        List<ChainDetail> addDetails = details.stream().filter(chainDetail -> Objects.isNull(chainDetail.getId())).collect(Collectors.toList());
        //所有待新增或更新的明细详情
        List<ChainDetail> allDetails = new ArrayList<>(addDetails);
        if(CollectionUtil.isNotEmpty(addDetails)){
            addDetails.forEach(e -> {
                e.setChainId(chain.getId());
                e.setPlanId(chain.getPlanId());
                e.setCreateBy(SecurityUtils.getUsername());
                e.setCreateTime(new Date());
                checkMaxSpuNum(chain, e);
            });

            chainDetailService.saveBatch(addDetails);
        }

        //修改
        List<ChainDetail> updateDetails = details.stream().filter(chainDetail -> Objects.nonNull(chainDetail.getId())).collect(Collectors.toList());
        if(CollectionUtil.isNotEmpty(updateDetails)){
            updateDetails.forEach(e -> {
                e.setUpdateBy(SecurityUtils.getUsername());
                e.setUpdateTime(new Date());
                checkMaxSpuNum(chain, e);
            });
            chainDetailService.updateBatchById(updateDetails);
        }
        allDetails.addAll(updateDetails);

        

        //删除操作 拿到要删除的明细id
        List<ChainDetail> deleteDetails = dbChainDetails.stream().filter(e -> !updateDetails.stream().map(ChainDetail::getId).collect(Collectors.toList()).contains(e.getId())).collect(Collectors.toList());
        if(CollectionUtil.isNotEmpty(deleteDetails)){
            deleteDetails.forEach(e -> {
                e.setDelFlag("2");
                e.setUpdateBy(SecurityUtils.getUsername());
                e.setUpdateTime(new Date());
            });
            chainDetailService.updateBatchById(deleteDetails);
        }

    }

    private static void checkMaxSpuNum(Chain chain, ChainDetail e) {
        if(Objects.nonNull(chain.getMaxPickNum()) && Objects.nonNull(e.getMaxSpuNum()) && e.getMaxSpuNum() > chain.getMaxPickNum()){
            throw new CustomException(e.getSpuCode()+"款号，同款件数超过最大可选件数，请检查");
        }
    }

    private Chain checkUpdate(Chain chain,Chain dbChain) {
        //校验spu名称相同 的最大同款件数是否相同 是否有相同的颜色规格
        checkSpuColorSize(chain);
        if(Objects.isNull(chain.getBeginDate()) || Objects.isNull(chain.getEndDate())){
            throw new CustomException("计划开始时间和结束时间不能为空");
        }

        List<Chain> dbChains = baseMapper.selectList(Wrappers.<Chain>lambdaQuery().in(Chain::getPlanId, chain.getPlanId()).eq(Chain::getDelFlag, "0"));

        List<Chain> chainList = dbChains.stream().map(e ->
                Objects.equals(e.getId(), chain.getId()) ? chain : e
        ).collect(Collectors.toList());

        checkNameUnique(chainList);

        if(Objects.isNull(dbChain)){
            throw new CustomException("接龙链接不存在");
        }
        if(Objects.nonNull(dbChain.getEndDate()) && new Date().after(dbChain.getEndDate())){
            throw new CustomException("接龙链接已结束无法修改");
        }
        // 进行中判断是否修改了开始时间
        if(!Objects.equals(dbChain.getBeginDate(), chain.getBeginDate())
                && new Date().before(dbChain.getEndDate())
                && new Date().after(dbChain.getBeginDate()) ){
            throw new CustomException("进行中的只允许修改接龙结束时间");
        }
        checkMustFiled(chain);
        return dbChain;
    }

    @Transactional
    @Override
    public void deleteLink(List<Long> chainIds) {
        if(CollectionUtil.isNotEmpty(chainIds)){
            LambdaQueryWrapper<Chain> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.in(Chain::getId, chainIds).eq(Chain::getDelFlag, "0");
            List<Chain> chains = this.list(queryWrapper);
            chains.forEach(e -> {
                Integer count = orderMapper.selectCount(Wrappers.<ChainOrder>lambdaQuery()
                        .eq(ChainOrder::getChainId, e.getId())
                        .eq(ChainOrder::getDelFlag, "0")
                );
                if(count > 0){
                    throw new CustomException("【"+e.getName()+ "】已经存在接龙订单，不允许删除");
                }
            });

//            List<Chain> chainList = chains.stream().filter(e -> Objects.nonNull(e.getBeginDate()) && new Date().after(e.getBeginDate())).collect(Collectors.toList());

//            if(CollectionUtil.isNotEmpty(chainList)){
//                throw new CustomException("进行中或已结束的接龙链接无法删除【"+chainList.get(0).getName()+ "】");
//            }
            extracted(chainIds, queryWrapper);

            ChainDetail query = new ChainDetail();
            query.setDelFlag("0");
            List<ChainDetail> deleteDetails = chainDetailService.list(
                    Wrappers.query(query).lambda().in(ChainDetail::getChainId, chainIds)
            );
            //删除
            if(CollectionUtil.isNotEmpty(deleteDetails)){
                deleteDetails.forEach(e -> {
                    e.setDelFlag("2");
                    e.setUpdateTime(new Date());
                    e.setUpdateBy(SecurityUtils.getUsername());
                });
                chainDetailService.updateBatchById(deleteDetails);
            }
        }
    }



    private List<List<String>> genHeaders(String header1, List<String> dynamicHeaders){

        List<List<String>> headList = new ArrayList<>();
        // 固定表头
        headList.add(Collections.singletonList(header1));
        // 动态扩展表头（如从数据库读取字段）
        for (String header : dynamicHeaders) {
            headList.add(Collections.singletonList(header));
        }
        return headList;
    }


    private void extracted(List<Long> chainIds, LambdaQueryWrapper<Chain> queryWrapper) {
        Chain chain = new Chain();
        chain.setIds(chainIds);
        chain.setDelFlag("2");
        chain.setUpdateTime(new Date());
        chain.setUpdateBy(SecurityUtils.getUsername());
        this.update(chain, queryWrapper);
    }


    /**
     * 生成短链接
     * @param chain
     * @return
     */
    @Override
    public String genLink(Chain chain) {
        GenerateShortLinkRequest shortLinkRequest = GenerateShortLinkRequest.builder()
                .pageUrl("pages/goods/linkDetail?id=" + chain.getId())
//                .pageUrl("pages/goods/linkDetail")
//                .pageTitle(chain.getName())
                .isPermanent(false)
                .build();
        return WxUtil.genLink(shortLinkRequest);
    }

    @Override
    public ChainDetail detail(Long planId,String skuCode) {
        if(Objects.isNull(planId) || Objects.isNull(skuCode)){
            return null;
        }
        List<Chain> chains = baseMapper.selectList(Wrappers.<Chain>lambdaQuery().eq(Chain::getPlanId, planId).eq(Chain::getDelFlag, "0"));
        Map<Long, Chain> chainGroup = chains.stream().collect(Collectors.toMap(
                Chain::getId,
                Function.identity(),
                (e, r) -> r
        ));

        if(CollectionUtil.isNotEmpty(chains)){
            List<Long> chainIds = chains.stream().map(Chain::getId).collect(Collectors.toList());
            List<ChainDetail> chainDetails = chainDetailService.list(
                    Wrappers.query(new ChainDetail()).lambda()
                            .eq(ChainDetail::getDelFlag, "0")
                            .in(ChainDetail::getChainId, chainIds)
                            .eq(ChainDetail::getSkuCode, skuCode)
            );
            if(CollectionUtil.isEmpty(chainDetails)){
                return null;
            }
            ChainDetail chainDetail = chainDetails.get(0);
            Chain chain = chainGroup.get(chainDetail.getChainId());
            chainDetail.setSpuName(chain.getName() + "-" + chainDetail.getSpuName());
            return chainDetail;
        }
        return null;
    }
}
